//
// Created by Administrator on 2023/11/28.
//


#include "upacker.h"



static void frame_decode(upacker_inst_t packer);
static int encode_frame(upacker_inst_t packer, uint16_t seq, uint16_t cmd, uint8_t crypto, uint8_t type, const uint8_t *payload, int payload_len);

static const char *UP_PACKER = "UP_PACKER";


static const char *UNP_PACKER = "UNP_PACKER";


/**
 * @brief  结构体初始化
 * @note
 * @param  *packer:
 * @param  *handler:
 * @retval None
 */
int upacker_init(upacker_inst_t packer, PACKER_CB h, PACKER_SB  s){

    packer->cb = h;
    packer->send = s;
    return 0;
}

//包数据解析处理
static void frame_decode(upacker_inst_t packer){
    esp_log_level_set(UP_PACKER, ESP_LOG_INFO);
    while(1){
        if(packer->cnt < 2) {
            break;
        }
        if (packer->data[0] != 0x55 || packer->data[1] != 0x55) {
            memmove(packer->data, packer->data + 1, packer->cnt - 1);
            packer->cnt--;
            continue;
        }
        if (packer->cnt < 4) {
            break;
        }
        int frame_len = packer->data[2] << 8 | packer->data[3];
        if(frame_len > MAX_PACK_SIZE) {
            //remove first byte
            memmove(packer->data, packer->data + 1, packer->cnt - 1);
            packer->cnt--;
            ESP_LOGI(UP_PACKER, "flen error: %d", frame_len);
            continue;
        }
        if (packer->cnt < frame_len) {
            break;
        }
        if (packer->data[frame_len - 2] != 0xAA || packer->data[frame_len - 1] != 0xAA) {
            //remove first byte
            memmove(packer->data, packer->data + 1, packer->cnt - 1);
            packer->cnt--;
            ESP_LOGI(UP_PACKER, "end error: %02X %02X", packer->data[frame_len - 2], packer->data[frame_len - 1]);
            continue;
        }
        uint8_t bcc = 0;
        for (int i = 0; i < frame_len- 3; i++) {
            bcc += packer->data[i];
        }
        if (bcc != packer->data[frame_len - 3]) {
            //remove first byte
            memmove(packer->data, packer->data, packer->cnt - 1);
            packer->cnt--;
            ESP_LOGI(UP_PACKER, "bcc error: %02X != %02X", bcc, packer->data[frame_len - 3]);
            continue;
        }

        uint8_t *data = packer->data + 5;
        int data_len = frame_len - 8;
        int effect_data_len = data_len;
        uint8_t crypto = packer->data[4];
        if(crypto == 0) {
            //do nothing
        } else if(crypto == 1) {
            //crypto, aes128
            //effect_data_len = xaes_decrypt(data, data_len);
            if(effect_data_len < 0) {
                //remove frame from buffer
                memmove(packer->data, packer->data + frame_len, packer->cnt - frame_len);
                packer->cnt -= frame_len;
                ESP_LOGI(UP_PACKER, "aes_decrypt error");
                continue;
            }
        } else {
            //unknown crypto
            //remove frame from buffer
            memmove(packer->data, packer->data + frame_len, packer->cnt - frame_len);
            packer->cnt -= frame_len;
            ESP_LOGI(UP_PACKER, "unknown crypto: %d", crypto);
            continue;
        }
        uint8_t type = data[0];
        uint16_t seq = data[1] << 8 | data[2];
        uint16_t cmd = data[3] << 8 | data[4];
        uint8_t *payload = data + 5;
        int payload_len = effect_data_len - 5;
        packer->cb(type, seq, cmd, payload, payload_len);
        //remove frame from buffer
        memmove(packer->data, packer->data + frame_len, packer->cnt  - frame_len);
        packer->cnt  -= frame_len;
    }
}

/**
 * @brief  解包输入数据
 * @note
 * @param  cmd_packer:
 * @param  *buff:
 * @param  size:
 * @retval None
 */
void upacker_unpack(upacker_inst_t packer, const uint8_t *buff, uint16_t size)
{
    for (uint16_t i = 0; i < size; i++)
    {
        packer->data[packer->cnt++] = buff[i];
    }
    frame_decode(packer);
}

//封包数据处理
static int encode_frame(upacker_inst_t packer, uint16_t seq, uint16_t cmd, uint8_t crypto, uint8_t type, const uint8_t *payload, int payload_len){
    uint8_t bcc = 0;
    esp_log_level_set(UNP_PACKER, ESP_LOG_INFO);
    packer->cnt_send = 0;

    packer->send_data[packer->cnt_send++] = 0x55;
    packer->send_data[packer->cnt_send++] = 0x55;
    //reserve 2 bytes for frame_len
    packer->cnt_send += 2;

    packer->send_data[packer->cnt_send++] = crypto;
    ESP_LOGI(UNP_PACKER, "crypto: %d", crypto);

    //type
    packer->send_data[packer->cnt_send++] = type;
    ESP_LOGI(UNP_PACKER, "type: %d", type);

    //seq
    packer->send_data[packer->cnt_send++] = (seq >> 8) & 0xFF;
    packer->send_data[packer->cnt_send++] = seq & 0xFF;
    ESP_LOGI(UNP_PACKER, "seq: %d", seq);

    //cmd
    packer->send_data[packer->cnt_send++] = (cmd >> 8) & 0xFF;
    packer->send_data[packer->cnt_send++] = cmd & 0xFF;

    for(int i = 0; i < payload_len; i++) {
        packer->send_data[packer->cnt_send++] = payload[i];
    }
    if(crypto == 0) {
        //no crypto
    } else if(crypto == 1) {
        //todo crypto, aes128
    } else {
        //unknown crypto
        ESP_LOGI(UNP_PACKER, "unknown crypto: %d", crypto);
        return -1;
    }
    packer->cnt_send += 1;
    //0xaaaa
    packer->send_data[packer->cnt_send++] = 0xAA;
    packer->send_data[packer->cnt_send++] = 0xAA;

    //fill frame_len
    packer->send_data[2] = (packer->cnt_send >> 8) & 0xFF;
    packer->send_data[3] = packer->cnt_send & 0xFF;
    //fill bcc
    for(int i = 0; i < packer->cnt_send - 3; i++) {
        bcc += packer->send_data[i];
        ESP_LOGI(UNP_PACKER, "i: %d", i);
        ESP_LOGI(UNP_PACKER, "date: %d", packer->send_data[i]);
        ESP_LOGI(UNP_PACKER, "bcc: %d", bcc);
    }
    packer->send_data[packer->cnt_send - 3] = bcc;
    return 0;
}

/**
 * @brief  封包数据并发送
 * @note
 * @param  *packer:
 * @param  *buff:
 * @param  size:
 * @retval None
 */
void upacker_pack(upacker_inst_t packer, uint16_t seq, uint16_t cmd, uint8_t crypto, uint8_t type, const uint8_t *payload, int payload_len)
{
    if(encode_frame(packer, seq, cmd, crypto, type, payload, payload_len) == 0){
        packer->send(packer->send_data, packer->cnt_send);
    }
}










